home *** CD-ROM | disk | FTP | other *** search
/ Compendium Deluxe 1 / LSD Compendium Deluxe 1.iso / a / text / manipulation / snap164.lha / snapchars.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-11-30  |  24.5 KB  |  891 lines

  1. #if __SASC
  2. #include "snap.h"
  3. #endif
  4.  
  5. int MergePlanes(struct BitMap *src);
  6.  
  7. /* Auto: make
  8. */
  9.  
  10. IMPORT struct SnapRsrc *SnapRsrc;
  11.  
  12. #define COPY 0xC0L
  13. #define INVCOPY 0x30L
  14. #define CopyChar(_x, _y, _m)                                  \
  15.     BltBitMap(&MyBM, (LONG)_x, (LONG)_y,                      \
  16.       &TempBM, 0L, 0L, (LONG)FontWidth, (LONG)FontHeight,     \
  17.       _m, -1L, NULL);                                         \
  18.     WaitBlit()
  19.  
  20. WORD Unit;
  21. UWORD Pattern[5] = {
  22.     0,
  23.     0x0c3f,     /* Frame ....oo....oooooo */
  24.     0x3333,     /* Char  ..oo..oo..oo..oo */
  25.     0x1f1f,     /* Word  ...ooooo...ooooo */
  26.     0xffff      /* Line  oooooooooooooooo */
  27. };
  28.  
  29. LONG xl; /* leftmost x position */
  30. LONG xr; /* rightmost x position */
  31. LONG yt; /* topmost y position */
  32. LONG yb; /* bottommost y position */
  33. LONG minx; /* left limit */
  34. LONG maxx; /* right limit */
  35. LONG maxy; /* bottom limit */
  36. LONG tl, tr; /* used by findword - left and right edge of word */
  37. WORD fw, fh; /* Font width and height used when drawing the frame */
  38. WORD GZZ;
  39. WORD SBM;
  40.  
  41. LONG mx, my; /* Mouse position in character steps */
  42. #define closetop     0
  43. #define closebottom  1
  44. WORD closey;
  45. #define closeleft   0
  46. #define closeright  1
  47. WORD closex;
  48.  
  49.  
  50. struct Window *window;  /* The window we're snapping from */
  51.  
  52. /* Data for font being snapped */
  53. UWORD FontHeight;
  54. UWORD FontWidth;
  55. UWORD Underscore;
  56. UBYTE FontType;
  57. UBYTE LoChar;
  58. UBYTE HiChar;
  59. UWORD Modulo;
  60. UWORD *CharLoc;
  61. UWORD *CharKern;
  62. UBYTE *SrcData;
  63. IMPORT UBYTE *CharData;
  64. UBYTE IFlags;
  65.  
  66. IMPORT struct RastPort TempRp, MyRP;
  67. IMPORT struct BitMap TempBM, MyBM;
  68.  
  69. IMPORT UWORD *TempRaster;   /* Used for character recognition */
  70.  
  71. IMPORT struct Screen *theScreen;
  72. IMPORT struct RastPort rp;
  73. struct Layer *LockedLayer;
  74.  
  75. IMPORT struct timerequest MyTR;
  76.  
  77. IMPORT LONGBITS cancelsignal, donesignal, movesignal;
  78. IMPORT LONGBITS clicksignal, ticksignal, timersignal;
  79. IMPORT WORD action;
  80.  
  81. WORD starting;
  82.  
  83. /* Init vars with font data.
  84. */
  85.  
  86. WORD SetSnapFont(font)
  87. struct TextFont *font;
  88. {
  89.     if (!font) {
  90.         return 0;
  91.     }
  92.     FontHeight = font->tf_YSize;
  93.     if (FontHeight > CHEIGHT) {
  94.         return 0;
  95.     }
  96.     Underscore = font->tf_Baseline + 1;
  97.     FontType = font->tf_Flags;
  98.     if (FontType & FPF_PROPORTIONAL) {
  99.         return 0;
  100.     }
  101.     FontWidth = font->tf_XSize;
  102.     LoChar = font->tf_LoChar;
  103.     HiChar = font->tf_HiChar;
  104.     Modulo = font->tf_Modulo;
  105.     CharLoc = (UWORD *)font->tf_CharLoc;
  106.     CharKern = (UWORD *)font->tf_CharKern;
  107.     Modulo = font->tf_Modulo;
  108.     SrcData = (UBYTE *)font->tf_CharData;
  109.     BltClear((char *)CharData, 256L * (CHEIGHT * 2), 0L);
  110.     WaitBlit();
  111.     CopyFont();
  112.     return 1;
  113. }
  114.  
  115. /* Check if the character at x, y is a space
  116. */
  117.  
  118. WORD IsSpace(x, y)
  119. LONG x, y;
  120. {
  121.     REGISTER WORD i = FontHeight - 1;
  122.     REGISTER UWORD *data = &TempRaster[i];
  123.  
  124.       /* Copy character at x, y */
  125.     BltClear((char *)TempRaster, CHEIGHT * 2L, 0L);
  126.     ClipBlit(&rp, x, y,
  127.       &TempRp, 0L, 0L, (LONG)FontWidth, (LONG)FontHeight, COPY);
  128.     WaitBlit();
  129.  
  130.     if (*data) {         /* Try inverted copy */
  131.         ClipBlit(&rp, x, y,
  132.           &TempRp, 0L, 0L, (LONG)FontWidth, (LONG)FontHeight, INVCOPY);
  133.         WaitBlit();
  134.     }
  135.     while (i--) {
  136.         if (*data--) {
  137.             return 0;
  138.         }
  139.     }
  140.     return 1;
  141. }
  142.  
  143. #define ShortFrame 4L      /* Square frame - columnar select */
  144. #define LongFrame  8L      /* Strange frame - char or word select */
  145. IMPORT LONG OFType;        /* Old frame type: ShortFrame/LongFrame */
  146. IMPORT UWORD Ptrn;
  147. IMPORT Point OldFrame[];
  148. IMPORT Point NewFrame[];
  149.  
  150.  
  151. /* update_frame calculates the new frame,
  152. ** erases the old frame and draws the new one.
  153. ** It's all pretty obvious if you take it slowly.
  154. */
  155. VOID update_frame()
  156. {
  157.     LONG ft;
  158.     REGISTER LONG l, b, r, t, ml, mr;
  159.     l = xl - 1;
  160.     r = xr + fw;
  161.     t = yt - 1;
  162.     b = yb + fh;
  163.     ml = minx - 1;
  164.     mr = maxx + fw;
  165.     if (l < 0)                  l = 0;
  166.     if (r > window->Width - 1)  r = window->Width - 1;
  167.     if (t < 0)                  t = 0;
  168.     if (b > window->Height - 1) b = window->Height - 1;
  169.     if (ml < 0)                 ml = 0;
  170.     if (mr > window->Width - 1) mr = window->Width - 1;
  171.  
  172.     switch (Unit) {
  173.         case UNIT_FRAME: {
  174.               /*********\
  175.               *         *
  176.               *         *
  177.               \*********/
  178.             NewFrame[0].x = l;  NewFrame[0].y = t;
  179.             NewFrame[1].x = r;  NewFrame[1].y = t;
  180.             NewFrame[2].x = r;  NewFrame[2].y = b;
  181.             NewFrame[3].x = l;  NewFrame[3].y = b;
  182.             NewFrame[4].x = l;  NewFrame[4].y = t;
  183.             ft = ShortFrame;
  184.             break;
  185.         }
  186.         case UNIT_CHAR:
  187.         case UNIT_WORD: {
  188.             if (yt == yb) {   /* On the same line - same as UNIT_FRAME */
  189.                 NewFrame[0].x = l;  NewFrame[0].y = t;
  190.                 NewFrame[1].x = r;  NewFrame[1].y = t;
  191.                 NewFrame[2].x = r;  NewFrame[2].y = b;
  192.                 NewFrame[3].x = l;  NewFrame[3].y = b;
  193.                 NewFrame[4].x = l;  NewFrame[4].y = t;
  194.                 ft = ShortFrame;
  195.             } else {
  196.                       /*****\
  197.                  ******     *
  198.                  *          *
  199.                  *      *****
  200.                  *******/
  201.                 NewFrame[0].x = l;   NewFrame[0].y = t;
  202.                 NewFrame[1].x = mr;  NewFrame[1].y = t;
  203.                 NewFrame[2].x = mr;  NewFrame[2].y = yb;
  204.                 NewFrame[3].x = r;   NewFrame[3].y = yb;
  205.                 NewFrame[4].x = r;   NewFrame[4].y = b;
  206.                 NewFrame[5].x = ml;  NewFrame[5].y = b;
  207.                 NewFrame[6].x = ml;  NewFrame[6].y = yt + fh;
  208.                 NewFrame[7].x = l;   NewFrame[7].y = yt + fh;
  209.                 NewFrame[8].x = l;   NewFrame[8].y = t;
  210.                 ft = LongFrame;
  211.             }
  212.             break;
  213.         }
  214.         case UNIT_LINE: {
  215.             NewFrame[0].x = ml;  NewFrame[0].y = t;
  216.             NewFrame[1].x = mr;  NewFrame[1].y = t;
  217.             NewFrame[2].x = mr;  NewFrame[2].y = b;
  218.             NewFrame[3].x = ml;  NewFrame[3].y = b;
  219.             NewFrame[4].x = ml;  NewFrame[4].y = t;
  220.             ft = ShortFrame;
  221.             break;
  222.         }
  223.         default: {
  224.             break;
  225.         }
  226.     }
  227.     draw_frame(ft);
  228. }
  229.  
  230. VOID FindWord()
  231. {
  232.       /* Must remove frame to be able to search for spaces */
  233.     WaitTOF();
  234.     erase_frame();
  235.     tl = mx;
  236.       /* Find a space to the left... */
  237.     while (!IsSpace(tl, my)) {
  238.         tl -= fw;
  239.         if (tl < minx) {
  240.             break;
  241.         }
  242.     }
  243.     tl += fw;
  244.     tr = mx;
  245.       /* ...and to the right */
  246.     while (!IsSpace(tr, my)) {
  247.         tr += fw;
  248.         if (tr + fw > maxx) {
  249.             break;
  250.         }
  251.     }
  252.     tr -= fw;
  253.     if (tr < tl) {
  254.         tl = xl;
  255.         tr = xr;
  256.     }
  257. }
  258.  
  259. /* ChangeUnit cycles the unit of selection. The differents units
  260.    are: character, word and line.
  261. */
  262.  
  263. VOID ChangeUnit()
  264. {
  265.  
  266.     switch (Unit) {
  267.         case UNIT_FRAME: {
  268.             Unit = UNIT_CHAR;
  269.             break;
  270.         }
  271.         case UNIT_CHAR: {
  272.             Unit = UNIT_WORD;
  273.             FindWord();
  274.             xl = tl;
  275.             xr = tr;
  276.             break;
  277.         }
  278.         case UNIT_WORD: {
  279.             Unit = UNIT_LINE;
  280.             xl = minx;
  281.             xr = maxx;
  282.             break;
  283.         }
  284.         case UNIT_LINE: {
  285.             Unit = UNIT_FRAME;
  286.             xl = xr = mx;
  287.             break;
  288.         }
  289.     }
  290.     if (SnapRsrc->CrawlPtrn == 0) {
  291.         Ptrn = Pattern[Unit];
  292.     }
  293. }
  294.  
  295. /* ExtendSelection extends the current selection according to
  296.    the mouse position and the selected unit.
  297.    Note that ExtendSelection doesn't optimize moves that don't
  298.    make any difference. FIXME
  299. */
  300.  
  301. VOID ExtendSelection()
  302. {
  303.     /* Fix which row we're talking about */
  304.     if (closey == closetop) {       /* Find closest row */
  305.         yt = my;               /* change top row */
  306.     } else {
  307.         yb = my;               /* change bottom row */
  308.     }
  309.  
  310.     /* Take care of left and right character pos */
  311.     switch (Unit) {
  312.         case UNIT_FRAME: {
  313.             if (closex == closeleft) {
  314.                 xl = mx;
  315.             } else {
  316.                 xr = mx;
  317.             }
  318.             break;
  319.         }
  320.         case UNIT_CHAR: {
  321.             if (yt == yb) {            /* One line */
  322.                 if (closex == closeleft) {
  323.                     xl = mx;
  324.                 } else {
  325.                     xr = mx;
  326.                 }
  327.             } else {                    /* Multiple lines */
  328.                 if (yt == my) {
  329.                     xl = mx;            /* At top - set left */
  330.                 } else {
  331.                     xr = mx;            /* At bottom - set right */
  332.                 }
  333.             }
  334.             break;
  335.         }
  336.         case UNIT_WORD: {
  337.             FindWord();                 /* Find the word */
  338.             if (yt == yb) {             /* One line */
  339.                 if (closex == closeleft) {   /* Find closest char pos */
  340.                     xl = tl;
  341.                 } else {
  342.                     xr = tr;
  343.                 }
  344.             } else {                   /* Multiple lines */
  345.                 if (yt == my) {        /* Where am I */
  346.                     xl = tl;           /* At top - set left */
  347.                 } else {
  348.                     xr = tr;           /* At bottom - set right */
  349.                 }
  350.             }
  351.             break;
  352.         }
  353.         case UNIT_LINE: {              /* Always full width */
  354.             break;
  355.         }
  356.     }
  357.     if (yt - fh == yb) {
  358.         yb += fh;
  359.     }
  360.     if (yt == yb && xl - fw == xr) {
  361.         xr += fw;
  362.     }
  363.     if (xr > maxx) {         /* Check for window bounds */
  364.         xr = maxx;
  365.     }
  366.     if (xl < minx) {         /* Check for window bounds */
  367.         xl = minx;
  368.     }
  369.     if (yb > maxy) {         /* Check for window bounds */
  370.         yb = maxy;
  371.     }
  372.     if (xl > maxx) {
  373.         xl = maxx;
  374.     }   
  375.     if (xr < minx) {
  376.         xr = minx;
  377.     }   
  378. }
  379.  
  380. /* The actual character snapper. It actually works. :-) */
  381.  
  382. WORD SnapChars()
  383. {
  384.     LONG width;
  385.     LONG height;
  386.     UBYTE *SnapSpace;
  387.     ULONG SnapSize;
  388.     ULONG counter;
  389.     REGISTER LONG x, y;
  390.  
  391.       /* Check coordinates */
  392.     if (yt - fh == yb) {        /* No rows, shouldn't happen */
  393.         return 0;
  394.     }
  395.     if (yt == yb && xl - fw == xr) {     /* Nothing at all */
  396.         return 0;
  397.     }
  398.  
  399.       /* Calculate stuff */
  400.     width = maxx - (minx + 1) + fw + fw;  /* Add one for a LF */
  401.     height = yb - yt + fh;
  402.     SnapSize = ((width / fw) + 1) * (height / fh);
  403.     counter = 0;
  404.  
  405.       /* Initialize things */
  406.     InitRastPort(&MyRP);
  407.     InitBitMap(&MyBM, 2L, width, height);    /* 1L */
  408.     MyRP.BitMap = &MyBM;
  409.     SnapSpace = AllocMem(SnapSize, MEMF_PUBLIC|MEMF_CLEAR);
  410.       /* Please insert more memory */
  411.     if (!SnapSpace) {
  412.         return 0;
  413.     }
  414.     MyBM.Planes[0] = AllocRaster(width, height);
  415.     if (!MyBM.Planes[0]) {
  416.         FreeMem(SnapSpace, SnapSize);
  417.         return 0;
  418.     }
  419.     MyBM.Planes[1] = AllocRaster(width, height);
  420.     if (!MyBM.Planes[1]) {
  421.         FreeMem(SnapSpace, SnapSize);
  422.         FreeRaster(MyBM.Planes[0], width, height);
  423.         return 0;
  424.     }
  425.     IFlags = 0;
  426.     
  427.       /* Make a local copy of the snapped chars */
  428.     ClipBlit(&rp, minx, yt, &MyRP, 0L, 0L, width, height, COPY);
  429.  
  430.       /* JEW: My additions. To fix the 2.0x hightlighted character
  431.               it merges plane 1 with plane 0. */
  432.     MergePlanes(&MyBM);
  433.  
  434.  
  435.       /* Ok, now we've got a copy of the character data */
  436.       /* Now it's ok to mess with the layers again */
  437.     UnlockLayer(LockedLayer);
  438.  
  439.       /* Clear our work area */
  440.     BltClear((char *)TempRaster, CHEIGHT * 2, 0L);
  441.  
  442.       /* Calculate bounds */
  443.     xl -= minx;
  444.     xr -= minx;
  445.     maxx -= minx;
  446.     minx = 0;
  447.     yb -= yt;
  448.     yt = 0;
  449.  
  450.       /* Single line - needs to be handled separately */
  451.     if (yt == yb) { /* Ok, we've got one */
  452.  
  453.           /* Read from left to right */
  454.         for (x = xl; x <= xr; x += fw, counter++) {
  455.             CopyChar(x, yt, COPY);
  456.             if (!(SnapSpace[counter] = interpret(TempRaster))) {
  457.                 SnapSpace[counter] = SnapRsrc->BadChar;  /* Unrecognized */
  458.             }
  459.         }
  460.         if (Unit == UNIT_LINE) {
  461.             while (counter && SnapSpace[counter-1] == ' ') {
  462.                 counter--;
  463.             }
  464.         }
  465.     } else { /* Multiple lines */
  466.  
  467.         if (Unit == UNIT_FRAME) {
  468.             minx = xl;
  469.             maxx = xr;
  470.         }
  471.  
  472.           /* Read first line */
  473.         for (x = xl; x <= maxx; x += fw, counter++) {
  474.             CopyChar(x, yt, COPY);
  475.             if (!(SnapSpace[counter] = interpret(TempRaster))) {
  476.                 SnapSpace[counter] = SnapRsrc->BadChar;  /* Unrecognized */
  477.             }
  478.         }
  479.         if (Unit == UNIT_FRAME) {
  480.             SnapSpace[counter++] = 10;
  481.         } else {
  482.             SHORT endspace = (SnapSpace[counter-1] == ' ');
  483.               /* Remove trailing blanks */
  484.             while (counter && SnapSpace[counter-1] == ' ') {
  485.                 counter--;
  486.             }
  487.             if (endspace || !(SnapRsrc->flags & JOINLONG)) {
  488.                 SnapSpace[counter++] = 10;
  489.             }
  490.         }
  491.  
  492.           /* If more than two rows - read full middle rows */
  493.         if (yt + fh != yb) {
  494.             for (y = yt + fh; y < yb; y += fh) {
  495.                 for (x = minx; x <= maxx; x += fw, counter++) {
  496.                     CopyChar(x, y, COPY);
  497.                     if (!(SnapSpace[counter] = interpret(TempRaster))) {
  498.                         SnapSpace[counter] = SnapRsrc->BadChar;  /* Unrecognized */
  499.                     }
  500.                 }
  501.                 if (Unit == UNIT_FRAME) {
  502.                     SnapSpace[counter++] = 10;
  503.                 } else {
  504.                     SHORT endspace = (SnapSpace[counter-1] == ' ');
  505.                       /* Remove trailing blanks */
  506.                     while (counter && SnapSpace[counter-1] == ' ') {
  507.                         counter--;
  508.                     }
  509.                     if (endspace || !(SnapRsrc->flags & JOINLONG)) {
  510.                         SnapSpace[counter++] = 10;
  511.                     }
  512.                 }
  513.             }
  514.         }
  515.  
  516.           /* Read last line */
  517.         for (x = minx; x <= xr; x += fw, counter++) {
  518.             CopyChar(x, yb, COPY);
  519.             if (!(SnapSpace[counter] = interpret(TempRaster))) {
  520.                 SnapSpace[counter] = SnapRsrc->BadChar;  /* Unrecognized */
  521.             }
  522.         }
  523.         /* Remove trailing blanks */
  524.         while (counter && SnapSpace[counter-1] == ' ') {
  525.             counter--;
  526.         }
  527.     }
  528.     FreeRaster(MyBM.Planes[0], width, height);
  529.     FreeRaster(MyBM.Planes[1], width, height);
  530.     SaveClip(SnapSpace, counter);
  531.     FreeMem(SnapSpace, SnapSize);
  532.     return 1;
  533. }
  534.  
  535.  
  536. /* HandleChars is the part of the Snap state machine that handles
  537.    snapping of characters. The selection is done in different
  538.    units: char, word, line.
  539. */
  540.  
  541. WORD HandleChars()
  542. {
  543.     LONG xoff, yoff;
  544.     LONG ox, oy;
  545.     LONG gzzx, gzzy, normalx, normaly;
  546.  
  547.       /* Find out which screen we're working on */
  548.     theScreen = WhichScreen();
  549.  
  550.       /* Oops, no screen? */
  551.     if (!theScreen) {
  552.         action = noaction;
  553.         return 0;
  554.     }
  555.  
  556.       /* Ok, what window? */
  557.     window = WhichWindow(theScreen);
  558.  
  559.       /* Oh dear, no window. */
  560.     if (!window) {
  561.         action = noaction;
  562.         return 0;
  563.     }
  564.  
  565.       /* Try to get these as early as possible */
  566.     gzzx = window->GZZMouseX;
  567.     gzzy = window->GZZMouseY;
  568.     normalx = window->MouseX;
  569.     normaly = window->MouseY;
  570.  
  571.       /* No messing with the layers while I think */
  572.     LockedLayer = window->WLayer;
  573.     LockLayer(0L, LockedLayer);
  574.  
  575.       /* Don't want to wreck somebody's rastport */
  576.     CopyMem((char *)window->RPort, (char *)&rp, (LONG)sizeof(struct RastPort));
  577.  
  578.       /* Or his picture */
  579.     SetDrMd(&rp, COMPLEMENT);
  580.     rp.Mask = SnapRsrc->FrameMask;
  581.  
  582.     if (window->Flags & GIMMEZEROZERO) {
  583.         GZZ = 1;
  584.     } else {
  585.         GZZ = 0;
  586.     }
  587.     if (window->Flags & SUPER_BITMAP) {
  588.         SBM = 1;
  589.     } else {
  590.         SBM = 0;
  591.     }
  592.  
  593.       /* Find a position */
  594.     xl = (GZZ ? gzzx : normalx) + window->RPort->Layer->Scroll_X;
  595.     yt = (GZZ ? gzzy : normaly) + window->RPort->Layer->Scroll_Y;
  596.  
  597.     if (xl < 0) {
  598.         xl = 0;
  599.     }
  600.     if (yt < 0) {
  601.         yt = 0;
  602.     }
  603.  
  604.       /* Check your position */
  605.     if (xl > (GZZ ? window->GZZWidth : window->Width) ||
  606.       yt > (GZZ ? window->GZZHeight : window->Height)) {
  607.         UnlockLayer(LockedLayer);
  608.         action = noaction;
  609.         return 0;
  610.     }
  611.     IFlags = 0;
  612.  
  613.       /* Find out the offset for the clicked character, if any.
  614.       ** This is the part that makes it special. Simple, isn't it. Hah!
  615.       */
  616.     {
  617.         REGISTER struct CacheWindow *cw = GetCachedWindow(theScreen, window);
  618.         struct TextFont *font[3];
  619.         WORD fonts = 0;
  620.  
  621.           /* Collect fonts to try */
  622.         if (SnapRsrc->AlternateFont) {      /* The alternate font */
  623.             font[fonts++] = SnapRsrc->AlternateFont;
  624.         }
  625.         font[fonts++] = rp.Font;            /* Second best, the RP's font */
  626.         if (cw) {                           /* Best bet, the cached font */
  627.             font[fonts++] = cw->font;
  628.         }
  629.         while (fonts--) {
  630.             SHORT xadj;
  631.             SHORT yadj;
  632.             SHORT seekw;
  633.             SHORT seekh;
  634.               /* Find out what we're trying to read */
  635.             if (!SetSnapFont(font[fonts])) {
  636.                 continue;               /* Nope, try next font */
  637.             }
  638.  
  639.             BltClear((char *)TempRaster, CHEIGHT * 2, 0L);
  640.             if (cw) {
  641.                 xoff = - ((xl - cw->xoff) % cw->fw);
  642.                 yoff = - ((yt - cw->yoff) % cw->fh);
  643.                 ClipBlit(&rp, xl + xoff, yt + yoff,
  644.                   &TempRp, 0L, 0L, (LONG)FontWidth, (LONG)FontHeight, COPY);
  645.                 WaitBlit();
  646.                 if (interpret(TempRaster)) {
  647.                     goto found;
  648.                 }
  649.             }
  650.               /* No cache or cache didn't match */
  651.             xadj = (FontWidth < 8 ? FontWidth : 8);
  652.             yadj = (FontHeight < 12 ? FontHeight : 12);
  653.             seekw = (xadj << 1) - FontWidth;
  654.             seekh = (yadj << 1) - FontHeight;
  655.             xl -= xadj;
  656.             yt -= yadj;
  657.             xoff = 0;
  658.             while (xoff < seekw) {
  659.                 ClipBlit(&rp, xl + xoff, yt,
  660.                   &TempRp, 0L, 0L, (LONG)FontWidth, CHEIGHT, COPY);
  661.                 WaitBlit();
  662.                 yoff = 0;
  663.                 while (yoff < seekh) {
  664.                     if (interpret(&TempRaster[yoff])) {
  665.                         goto found;
  666.                     }
  667.                     ++yoff;
  668.                 }
  669.                 ++xoff;
  670.             }
  671.  
  672.               /* No character found. Try next font. */
  673.             xl += xadj; /* Adjust to original values */
  674.             yt += yadj;
  675.         }
  676.         UnlockLayer(LockedLayer);
  677.         action = noaction;
  678.         return 0;
  679.  
  680. found:
  681.           /* Ok, now we know where to look for chars.
  682.           ** xoff and yoff is character position within our 16xCHEIGHT bitmap.
  683.           */
  684.         xl = xl + xoff;         /* Adjust x */
  685.         yt = yt + yoff;         /* Adjust y */
  686.  
  687.         fw = FontWidth;
  688.         fh = FontHeight;
  689.  
  690.         {
  691.             SHORT temp = fh;
  692.             while (temp <= fh + SnapRsrc->Leading) {  /* Check for extra pixel row */
  693.                 BltClear((char *)TempRaster, CHEIGHT * 2, 0L);
  694.                 ClipBlit(&rp, xl, yt + temp,
  695.                   &TempRp, 0L, 0L, (LONG)FontWidth, (LONG)FontHeight, COPY);
  696.                 WaitBlit();
  697.                 if (interpret(TempRaster)) {
  698.                     fh = temp;
  699.                     break;
  700.                 }
  701.                 ++temp;
  702.             }
  703.         }
  704.  
  705.           /* Find out offsets within the window */
  706.         xoff = xl % fw;
  707.         yoff = yt % fh;
  708.  
  709.         if (cw) {
  710.             cw->xoff = xoff;
  711.             cw->yoff = yoff;
  712.             cw->fw = fw;
  713.             cw->fh = fh;
  714.             cw->font = font[fonts];
  715.         } else {
  716.             CacheWindow(window, xoff, yoff, fw, fh, font[fonts]);
  717.         }
  718.     }
  719.  
  720.       /* Set bounds */
  721.     minx = xoff;
  722.     maxx = minx +
  723.       (((GZZ ?
  724.         window->GZZWidth :
  725.         window->Width - window->BorderRight
  726.           /* Hack for borderless conman windows */
  727.         + (window->Flags & BORDERLESS && window->Flags & WINDOWSIZING ? 14 : 0))
  728.       - minx - fw) / fw) * fw;
  729.     maxy = yoff +
  730.       (((GZZ ? window->GZZHeight : window->Height) - yoff - fh) / fh) * fh;
  731.  
  732.       /* Check bounds */
  733.     if (xl > maxx) {
  734.         UnlockLayer(LockedLayer);
  735.         action = noaction;
  736.         return 0;
  737.     }
  738.       /* Set box dimensions */
  739.     xr = xl;
  740.     yb = yt;
  741.     ox = xr;
  742.     oy = yt;
  743.  
  744.       /* Select unit while starting */
  745.     starting = 1;
  746.  
  747.       /* Starting unit is character or frame */
  748.     Unit = SnapRsrc->StartUnit;
  749.     Ptrn = (SnapRsrc->CrawlPtrn ? SnapRsrc->CrawlPtrn : Pattern[Unit]);
  750.     OFType = 0L;
  751.     update_frame();
  752.  
  753.       /* Get the state machine running */
  754.     FOREVER {
  755.           /* Wait for something to happen */
  756.         REGISTER LONGBITS sig;
  757.  
  758.         MyTR.tr_time.tv_secs = 0;
  759.         MyTR.tr_time.tv_micro = 500000;
  760.         MyTR.tr_node.io_Command = TR_ADDREQUEST;
  761.         SendIO((struct IORequest *)&MyTR);
  762.  
  763.         sig = Wait(movesignal | cancelsignal | donesignal |
  764.           clicksignal | ticksignal | timersignal);
  765.  
  766.         if ((sig & timersignal) && CheckIO((struct IORequest *)&MyTR)) {
  767.             WaitIO((struct IORequest *)&MyTR);
  768.             erase_frame();
  769.             UnlockLayer(LockedLayer);   /* Unlock things */
  770.             sig = Wait(ticksignal);     /* Wait for input handler to become avtive */
  771.             LockLayer(0L, LockedLayer); /* Re-lock */
  772.               /* I guess I should check to see that the window is still
  773.                  there. Aw, what the heck. Apologies to anyone who gets
  774.                  bitten by this. */
  775.             DisplayBeep(NULL);
  776.             update_frame();
  777.         } else {
  778.             AbortIO((struct IORequest *)&MyTR);
  779.             WaitIO((struct IORequest *)&MyTR);
  780.             SetSignal(0, timersignal);
  781.         }
  782.  
  783.         if ((sig & ticksignal) && (SnapRsrc->CrawlPtrn != 0xffff)) {
  784.             crawl_frame(0L);
  785.         }
  786.  
  787.         mx = (LONG)(GZZ ? window->GZZMouseX : window->MouseX)
  788.           + window->RPort->Layer->Scroll_X;
  789.         if (mx < 0) {
  790.             mx = 0;
  791.         }
  792.           /* Calculate which edge is closest */
  793.         if ((mx - xl) < (xr - mx)) {
  794.             closex = closeleft;
  795.         } else {
  796.             closex = closeright;
  797.         }
  798.           /* Only interested in real char pos */
  799.         mx = mx - ((mx - xoff) % fw);
  800.  
  801.         my = (LONG)(GZZ ? window->GZZMouseY : window->MouseY)
  802.           + window->RPort->Layer->Scroll_Y;
  803.         if (my < 0) {
  804.             my = 0;
  805.         }
  806.           /* Calculate which row is closest */
  807.         if ((my - yt) < (yb - my)) {
  808.             closey = closetop;
  809.         } else {
  810.             closey = closebottom;
  811.         }
  812.         my = my - ((my - yoff) % fh);
  813.  
  814.           /* Hey, it moves! It's alive!! */
  815.         if ((sig & movesignal) && (action == snaptext)) {
  816.             if (mx != ox || my != oy) {  /* Something's happened */
  817.                 ExtendSelection();
  818.                 update_frame();
  819.                 starting = 0;
  820.                 ox = mx;
  821.                 oy = my;
  822.                 sig &= ~clicksignal;
  823.             }
  824.         }
  825.  
  826.           /* Ok, forget it... */
  827.         if (sig & cancelsignal) {
  828.             erase_frame();
  829.             UnlockLayer(LockedLayer);
  830.             return 0;
  831.         }
  832.  
  833.           /* Click */
  834.         if ((sig & clicksignal) && (action == snaptext)) {
  835.               /* Selecting unit */
  836.             if (starting) {
  837.                 if (mx == ox && my == oy) {
  838.                     ChangeUnit();
  839.                     if (Unit == UNIT_CHAR) {
  840.                         ChangeUnit();
  841.                     }
  842.                     update_frame();
  843.                 } else if (Unit == UNIT_FRAME) {
  844.                     ChangeUnit();
  845.                     update_frame();
  846.                 }
  847.             }
  848.             if (mx != ox || my != oy) { /* Click in a new place */
  849.                 ExtendSelection();
  850.                 update_frame();
  851.                 starting = 0;
  852.                 ox = mx;
  853.                 oy = my;
  854.             }
  855.         }
  856.  
  857.           /* Finished */
  858.         if (sig & donesignal) {
  859.             erase_frame();
  860.             return SnapChars();
  861.         }
  862.     }
  863. }
  864.  
  865. int MergePlanes(struct BitMap *src)
  866. {
  867.   register int width, height;
  868.   struct BitMap bm0, bm1;
  869.  
  870.   width  = src->BytesPerRow*8;
  871.   height = src->Rows;
  872.  
  873.   InitBitMap( &bm0,   1, width, height );
  874.   InitBitMap( &bm1,   1, width, height );
  875.  
  876.   bm0.Planes[0] = src->Planes[0];
  877.   bm1.Planes[0] = src->Planes[1];
  878.  
  879.   BltBitMap(
  880.             &bm1,     0,      0,     /* src, x0, y0 */
  881.             &bm0,     0,      0,     /* dest,x1, y1 */
  882.                   width, height,     /*      dx, dy */
  883.             0xee,                    /* minterm     */
  884.             0xff,                    /* planepick   */
  885.             0                        /* tempA       */
  886.            );
  887.  return 0;
  888. }
  889.  
  890.  
  891.